#include "drv_lan8720.h"
#include "bsp.h"
#include "bsp_eth.h"

/* ETH 网络PHY */


/* reg define */

//LAN8720寄存器
#define LAN8720_REG_BCR         (0x0000U)
#define LAN8720_REG_BSR         (0x0001U)
#define LAN8720_REG_PHYI1R      (0x0002U)
#define LAN8720_REG_PHYI2R      (0x0003U)
#define LAN8720_REG_ANAR        (0x0004U)
#define LAN8720_REG_ANLPAR      (0x0005U)
#define LAN8720_REG_ANER        (0x0006U)
#define LAN8720_REG_ANNPTR      (0x0007U)
#define LAN8720_REG_ANNPRR      (0x0008U)
#define LAN8720_REG_MMDACR      (0x000DU)
#define LAN8720_REG_MMDAADR     (0x000EU)
#define LAN8720_REG_ENCTR       (0x0010U)
#define LAN8720_REG_MCSR        (0x0011U)
#define LAN8720_REG_SMR         (0x0012U)
#define LAN8720_REG_TPDCR       (0x0018U)
#define LAN8720_REG_TCSR        (0x0019U)
#define LAN8720_REG_SECR        (0x001AU)
#define LAN8720_REG_SCSIR       (0x001BU)
#define LAN8720_REG_CLR         (0x001CU)
#define LAN8720_REG_ISFR        (0x001DU)
#define LAN8720_REG_IMR         (0x001EU)
#define LAN8720_REG_PHYSCSR     (0x001FU)

//LAN8720 BCR寄存器各位描述  
#define LAN8720_VAL_BCR_SOFT_RESET          (0x8000U)
#define LAN8720_VAL_BCR_LOOPBACK            (0x4000U)
#define LAN8720_VAL_BCR_SPEED_SELECT        (0x2000U)
#define LAN8720_VAL_BCR_AUTONEGO_EN         (0x1000U)
#define LAN8720_VAL_BCR_POWER_DOWN          (0x0800U)
#define LAN8720_VAL_BCR_ISOLATE             (0x0400U)
#define LAN8720_VAL_BCR_RESTART_AUTONEGO    (0x0200U)
#define LAN8720_VAL_BCR_DUPLEX_MODE         (0x0100U) 

//LAN8720的BSR寄存器各位描述
#define LAN8720_VAL_BSR_100BASE_T4          (0x8000U)
#define LAN8720_VAL_BSR_100BASE_TX_FD       (0x4000U)
#define LAN8720_VAL_BSR_100BASE_TX_HD       (0x2000U)
#define LAN8720_VAL_BSR_10BASE_T_FD         (0x1000U)
#define LAN8720_VAL_BSR_10BASE_T_HD         (0x0800U)
#define LAN8720_VAL_BSR_100BASE_T2_FD       (0x0400U)
#define LAN8720_VAL_BSR_100BASE_T2_HD       (0x0200U)
#define LAN8720_VAL_BSR_EXTENDED_STATUS     (0x0100U)
#define LAN8720_VAL_BSR_AUTONEGO_CPLT       (0x0020U)
#define LAN8720_VAL_BSR_REMOTE_FAULT        (0x0010U)
#define LAN8720_VAL_BSR_AUTONEGO_ABILITY    (0x0008U)
#define LAN8720_VAL_BSR_LINK_STATUS         (0x0004U)
#define LAN8720_VAL_BSR_JABBER_DETECT       (0x0002U)
#define LAN8720_VAL_BSR_EXTENDED_CAP        (0x0001U)

//LAN8720 PHYSCSR寄存器各位描述
#define LAN8720_VAL_PHYSCSR_AUTONEGO_DONE   (0x1000U)
#define LAN8720_VAL_PHYSCSR_HCDSPEEDMASK    (0x001CU)
#define LAN8720_VAL_PHYSCSR_10BT_HD         (0x0004U)
#define LAN8720_VAL_PHYSCSR_10BT_FD         (0x0014U)
#define LAN8720_VAL_PHYSCSR_100BTX_HD       (0x0008U)
#define LAN8720_VAL_PHYSCSR_100BTX_FD       (0x0018U) 


/* IO define */
#define LAN_RESET_PORT  GPIOA
#define LAN_RESET_PIN   GPIO_PIN_6

/* static var */
#define LAN_ADDR        0

static ETH_HandleTypeDef *eth_hanle = NULL;


/* static func */
#define lan_read_reg(reg, val)      bsp_eth_read_phy_reg(LAN_ADDR, reg, val)
#define lan_write_reg(reg, val)     bsp_eth_write_phy_reg(LAN_ADDR, reg, val)


/**
 * @brief 开启自动协商功能
 * 
 */
static void drv_lan8720_auto_nego(void)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_BCR, &val);
    val |= LAN8720_VAL_BCR_AUTONEGO_EN;
    lan_write_reg(LAN8720_REG_BCR, val);
}


/* export func */

/**
 * @brief 初始化
 * 
 */
void drv_lan8720_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    uint32_t val;
    int sta;
    uint32_t timeout;
    uint8_t mac[6];

    /* LAN8720_RESET : PA6 */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LAN_RESET_PORT, &GPIO_InitStruct);

    /* 硬复位 */
    bsp_gpio_pin_clr(LAN_RESET_PORT, LAN_RESET_PIN);
    delay_ms(100);
    bsp_gpio_pin_set(LAN_RESET_PORT, LAN_RESET_PIN);
    delay_ms(50);

    val = HAL_GetCurrentCPUID();
    mac[0] = 0x11;
    mac[1] = 0x22;
    mac[2] = (val >> 24) & 0xFF;
    mac[3] = (val >> 16) & 0xFf;
    mac[4] = (val >> 8) & 0xFF;
    mac[5] = (val >> 0) & 0xFF;
    bsp_eth_set_mac(mac);

    bsp_eth_init();
    eth_hanle = bsp_eth_get_handle();

    /* 软复位 */
    sta = LAN8720_STATUS_ERROR;
    if (lan_write_reg(LAN8720_REG_BCR, LAN8720_VAL_BCR_SOFT_RESET) == 0) // LAN8720软件复位
    {
        //等待软件复位完成
        if (lan_read_reg(LAN8720_REG_BCR, &val) == 0)
        {
            timeout = 0;
            while (val & LAN8720_VAL_BCR_SOFT_RESET)
            {
                if (lan_read_reg(LAN8720_REG_BCR, &val))
                {
                    sta = LAN8720_STATUS_READ_ERROR;
                    printf("lan8720 write error\r\n");
                    break;
                }
                delay_ms(10);
                timeout++;
                if (timeout >= 500)
                {
                    printf("lan8720 softreset timeout\r\n");
                    break; //超时跳出,5S
                }
            }
            if ((val & LAN8720_VAL_BCR_SOFT_RESET) == 0)
            {
                printf("lan8720 softreset success\r\n");
            }
        }
        else
        {
            sta = LAN8720_STATUS_READ_ERROR;
            printf("lan8720 read error\r\n");
        }
    }
    else
    {
        sta = LAN8720_STATUS_WRITE_ERROR;
        printf("lan8720 write error\r\n");
    }

    drv_lan8720_auto_nego(); //开启自动协商功能

    if (sta == LAN8720_STATUS_OK) //如果前面运行正常就延时1s
        delay_ms(1000);           //等待1s

    /* 等待网络连接成功 */
    timeout = 0;
    while (drv_lan8720_get_link_status() <= LAN8720_STATUS_LINK_DOWN)
    {
        delay_ms(10);
        timeout++;
        if (timeout >= 200)
        {
            sta = LAN8720_STATUS_LINK_DOWN;
            printf("lan8720 link timouout\r\n");
            break; //超时跳出,5S
        }
    }
    val = drv_lan8720_get_link_status();
    if (val == LAN8720_STATUS_100MBITS_FULLDUPLEX)
        printf("LAN8720:100Mb/s FullDuplex\r\n");
    else if (val == LAN8720_STATUS_100MBITS_HALFDUPLEX)
        printf("LAN8720:100Mb/s HalfDuplex\r\n");
    else if (val == LAN8720_STATUS_10MBITS_FULLDUPLEX)
        printf("LAN8720:10Mb/s FullDuplex\r\n");
    else if (val == LAN8720_STATUS_10MBITS_HALFDUPLEX)
        printf("LAN8720:10Mb/s HalfDuplex\r\n");
    // return sta;
}

/**
 * @brief 打开power down模式
 * 
 */
void drv_lan8720_mode_powerdown_enable(void)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_BCR, &val);
    val |= LAN8720_VAL_BCR_POWER_DOWN;
    lan_write_reg(LAN8720_REG_BCR, val);
}

/**
 * @brief 关闭power down模式
 * 
 */
void drv_lan8720_mode_powerdown_disaable(void)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_BCR, &val);
    val &= ~LAN8720_VAL_BCR_POWER_DOWN;
    lan_write_reg(LAN8720_REG_BCR, val);
}

/**
 * @brief 使能回环测试模式
 * 
 */
void drv_lan8720_mode_loopback_enable(void)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_BCR, &val);
    val |= LAN8720_VAL_BCR_LOOPBACK;
    lan_write_reg(LAN8720_REG_BCR, val);
}

/**
 * @brief 关闭回环测试模式
 * 
 */
void drv_lan8720_mode_loopback_disable(void)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_BCR, &val);
    val &= ~LAN8720_VAL_BCR_LOOPBACK;
    lan_write_reg(LAN8720_REG_BCR, val);
}

/**
 * @brief 使能中断
 * 
 * @param interrupt 仅限于_drv_lan8720_it_e中定义的变量
 */
void drv_lan8720_it_enable(_drv_lan8720_it_e interrupt)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_IMR, &val);
    val |= (uint32_t)interrupt;
    lan_write_reg(LAN8720_REG_IMR, val);
}

/**
 * @brief 关闭中断
 * 
 * @param interrupt 仅限于_drv_lan8720_it_e中定义的变量
 */
void drv_lan8720_it_disable(_drv_lan8720_it_e interrupt)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_IMR, &val);
    val &= ~(uint32_t)interrupt;
    lan_write_reg(LAN8720_REG_IMR, val);
}

/**
 * @brief 清除中断标志位
 * 
 * @param interrupt 仅限于_drv_lan8720_it_e中定义的变量
 */
void drv_lan8720_it_clear(_drv_lan8720_it_e interrupt)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_ISFR, &val);
    val |= (uint32_t)interrupt;
    lan_write_reg(LAN8720_REG_ISFR, val);
}

/**
 * @brief 获取指定的中断标志位
 * 
 * @param interrupt 
 * @return uint8_t 1,目标标志位置位  0,,目标标志位清零
 */
uint8_t drv_lan8720_get_it_status(_drv_lan8720_it_e interrupt)
{
    uint32_t val = 0;
    uint8_t sta = 0;

    lan_read_reg(LAN8720_REG_ISFR, &val);
    if (val & interrupt) sta = 1;
    else sta = 0;
    return sta;
}

/**
 * @brief 获取连接状态
 * 
 * @return uint32_t 
 */
uint32_t drv_lan8720_get_link_status(void)
{
    uint32_t val = 0;

    //读取两次，确保读取正确
    lan_read_reg(LAN8720_REG_BSR, &val);
    lan_read_reg(LAN8720_REG_BSR, &val);

    //获取连接状态(硬件，网线的连接，不是TCP、UDP等软件连接！)
    if ((val & LAN8720_VAL_BSR_LINK_STATUS) == 0)
    {
        return LAN8720_STATUS_LINK_DOWN;
    }

    //获取自动协商状态
    lan_read_reg(LAN8720_REG_BCR, &val);
    if ((val&LAN8720_VAL_BCR_AUTONEGO_EN) != LAN8720_VAL_BCR_AUTONEGO_EN) //未使能自动协商
    {
        if (((val & LAN8720_VAL_BCR_SPEED_SELECT) == LAN8720_VAL_BCR_SPEED_SELECT) &&
            ((val & LAN8720_VAL_BCR_DUPLEX_MODE) == LAN8720_VAL_BCR_DUPLEX_MODE))
            return LAN8720_STATUS_100MBITS_FULLDUPLEX;
        else if ((val & LAN8720_VAL_BCR_SPEED_SELECT) == LAN8720_VAL_BCR_SPEED_SELECT)
            return LAN8720_STATUS_100MBITS_HALFDUPLEX;
        else if ((val & LAN8720_VAL_BCR_DUPLEX_MODE) == LAN8720_VAL_BCR_DUPLEX_MODE)
            return LAN8720_STATUS_10MBITS_FULLDUPLEX;
        else
            return LAN8720_STATUS_10MBITS_HALFDUPLEX;
    }
    else
    {
        lan_read_reg(LAN8720_REG_PHYSCSR, &val);
        if ((val & LAN8720_VAL_PHYSCSR_AUTONEGO_DONE) == 0)
            return LAN8720_STATUS_AUTONEGO_NOTDONE;
        if ((val & LAN8720_VAL_PHYSCSR_HCDSPEEDMASK) == LAN8720_VAL_PHYSCSR_100BTX_FD)
            return LAN8720_STATUS_100MBITS_FULLDUPLEX;
        else if ((val & LAN8720_VAL_PHYSCSR_HCDSPEEDMASK) == LAN8720_VAL_PHYSCSR_100BTX_HD)
            return LAN8720_STATUS_100MBITS_HALFDUPLEX;
        else if ((val & LAN8720_VAL_PHYSCSR_HCDSPEEDMASK) == LAN8720_VAL_PHYSCSR_10BT_FD)
            return LAN8720_STATUS_10MBITS_FULLDUPLEX;
        else
            return LAN8720_STATUS_10MBITS_HALFDUPLEX;
    }
}

/**
 * @brief 设置连接状态
 * 
 * @param sta 
 */
void drv_lan8720_set_link_status(int sta)
{
    uint32_t val = 0;

    lan_read_reg(LAN8720_REG_BCR, &val);
    //关闭连接配置，比如自动协商，速度和双工
    val &= ~(LAN8720_VAL_BCR_AUTONEGO_EN | LAN8720_VAL_BCR_SPEED_SELECT | LAN8720_VAL_BCR_DUPLEX_MODE);

    if (sta == LAN8720_STATUS_100MBITS_FULLDUPLEX) // 100M全双工
        val |= (LAN8720_VAL_BCR_SPEED_SELECT | LAN8720_VAL_BCR_DUPLEX_MODE);
    else if (sta == LAN8720_STATUS_100MBITS_HALFDUPLEX) // 100M半双工
        val |= LAN8720_VAL_BCR_SPEED_SELECT;
    else if (sta == LAN8720_STATUS_10MBITS_FULLDUPLEX) // 10M全双工
        val |= LAN8720_VAL_BCR_DUPLEX_MODE;

    lan_write_reg(LAN8720_REG_BCR,val);
}





